/*
 * @file unitTest.h
 *
 * @brief Holds public declarations for the Simply C unit test framework.
 * This framework is built around the idea of test suites, test cases and
 * assertions. In general, a test suite can be viewed as testing a
 * single C source file. This test suite contains multiple test cases.
 * Each test case can be viewed as testing an individual C function.
 * Within each test case, assertions are used to compare expected results
 * to actual results during unit test execution. The output of the unit
 * tests is recorded to standard out and to a log file which can be analyzed
 * after the unit tests are executed.
 *
 *    Example:
 *
 *    Consider a file called packetBuilder.c. This file contains a
 *    function that qualifies to be unit tested (it is well encapsulated,
 *    loosely coupled). This function is called buildConfigFrame() and
 *    it accesses the following data structure, also in this file:
 *
 *    static struct
 *    {
 *      int           headerId;
 *      unsigned char nodeNumber;
 *      unsigned long data;
 *    } configFrame;
 *   
 *    packetBuilder.c contains a function called packetBuilderUnitTests()
 *    Most likely, the unit test functions are conditionally compiled in
 *    the file.
 *
 *    #ifdef UNIT_TESTS
 *
 *    void packetBuilderUnitTests(void)
 *    {
 *      startTestSuite("Packet Builder Test Suite");
 * 
 *      // functions can be created that hold the test cases,
 *      // call as many as you like, there is no limit
 *      // to the number of test cases in a test suite
 *      testBuildConfigFrame();
 * 
 *      endTestSuite();
 *
 *      return;
 *    }
 *
 *    static void testBuildConfigFrame(void)
 *    {
 *       startTestCase("Verify Configuration Frame Build");
 *
 *      // do any prep work needed to set up, then call the function
 *      // that is under test
 *      prepForHighSpeedConfig();
 *      setConfigNode(HIGH_NODE);
 *      setConfigData(0x12345678);
 *
 *      buildConfigFrame();
 *
 *      // after calling build config frame, we know from the design that
 *      // the data structure, configFrame, should contain specific values,
 *      // verify that these are correct using the asserts
 *    
 *      assertEqInt(FAST_CONFIG_HEADER, configFrame.headerId,
 *        __FILE__, __LINE__);
 * 
 *      assertEqUnsignedChar(HIGH_NODE, configFrame.nodeNumber,
 *        __FILE__, __LINE__);
 *  
 *      assertEqUnsignedLong(0x12345678, configFrame.data,
 *        __FILE__, __LINE__);
 *
 *      // continue on with as many tests as necessary to fully
 *      // exercise the buildConfigFrame function
 *
 *      endTestCase(); 
 *    }
 *
 *    #endif // UNIT_TESTS
 *
 *    More than likely, there will be a main function somewhere that
 *    calls all the unit tests in a project:
 *
 *    void runAllUnitTests(void)
 *    {
 *      // turn logging on for the unit test framework,
 *      // this opens a file for logging
 *      unitTestLogOn("unitTestLog.txt");
 *
 *      // call all the unit test suites you want
 *      packetBuilderUnitTests();
 *
 *      // clean up and close the logging file
 *      unitTestlogOff();
 *    }
 *
 *
 *    SYSTEM REQUIREMENTS:
 *
 *    Assumptions:
 * 
 *    1) Unit testing is performed in a single thread.
 *    2) Only one test suite is executed at a time.
 *    3) Only one test case is executed at a time.
 *
 *    It is also assumed that the following library functions are provided by the
 *    environment:
 *
 *    1) snprintf
 *    2) vprintf
 *    3) vfprintf
 * 
 *    Error checking in the framework is limited to verifying that test suites
 *    and test cases are only called one at a time. Any other mis-use of the framework
 *    is allowed:)
 *
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, version 3 (GPLv3).
 *       
 */

#ifndef _UNITTEST_H_
#define _UNITTEST_H_

/**
 *  Declarations for unit test framework functions.
 */
extern void startTestSuite(const char *);
extern void endTestSuite(void);
extern void startTestCase(const char *);
extern void endTestCase(void);
extern void unitTestLogOn(char const *);
extern void unitTestLogOff(void);
extern bool unitTestAllSuccess(void);

/**
 *  Use these asserts to verify test results
 */
extern void assertEqBool(bool, bool, const char *, int);
extern void assertNotEqBool(bool, bool, const char *, int);

extern void assertEqChar(char, char, const char *, int);
extern void assertNotEqChar(char, char, const char *, int);
extern void assertEqUnsignedChar(unsigned char, unsigned char, const char * , int);
extern void assertNotEqUnsignedChar(unsigned char, unsigned char, const char * , int);

extern void assertEqInt(int, int, const char * , int);
extern void assertNotEqInt(int, int, const char * , int);
extern void assertEqUnsignedInt(unsigned int, unsigned int, const char * , int);
extern void assertNotEqUnsignedInt(unsigned int, unsigned int, const char * , int);

extern void assertEqShort(short, short, const char *, int);
extern void assertNotEqShort(short, short, const char *, int);
extern void assertEqUnsignedShort(unsigned short, unsigned short, const char * , int);
extern void assertNotEqUnsignedShort(unsigned short, unsigned short, const char * , int);

extern void assertEqLong(long, long, const char *, int);
extern void assertNotEqLong(long, long, const char *, int);
extern void assertEqUnsignedLong(unsigned long, unsigned long, const char * , int);
extern void assertNotEqUnsignedLong(unsigned long, unsigned long, const char *, int);

/**
 *  if you need floating point support, uncomment the following define
 */
#define FLOATING_POINT_NEEDED 1

#ifdef FLOATING_POINT_NEEDED

/**
 * set the relative error used to compare floats, this determines how close
 * floating point numbers need to be to each other in order to be considered
 * equal. This value can be changed to suit the application.
 */
#define MAX_FLOAT_RELATIVE_ERROR ((double) 0.00001) // 99.999% accuracy

/**
 * set the absolute error, this is used when floats are really close to
 * zero, but of different signs. This value can be changed to suit the
 * application.
 */
#define MAX_FLOAT_ABSOLUTE_ERROR ((double) 1.0e-37)

extern void assertEqFloat(float, float, const char *, int);
extern void assertNotEqFloat(float, float, const char *, int);
extern void assertFloatClose(float, float, float, const char *, int);
extern void assertEqDouble(double, double, const char *, int);
extern void assertNotEqDouble(double, double, const char *, int);
extern void assertDoubleClose(double, double, double, const char *, int);
extern void assertLongDoubleClose(long double, long double, long double, const char *, int);

#endif

#endif  // _UNITTEST_H_



